# -*- coding: utf-8 -*-
"""
Created on Mon Aug 27 12:33:04 2012

@author: Tomek
"""

import CPPparse
import PrintClass
def checkLuaType(st):
    if len(st)<4:
        return False
    if st[len(st)-7:]=="_LUAREF" or st[len(st)-7:]=="_LUAPTR" or st[len(st)-4:]=="_LUA":
        return True
    else:
        return False
def getOldTypeFromLua(st):
    if len(st)<4:
        return st
    if st[len(st)-7:]=="_LUAREF":
        return st[:len(st)-7]+"&"
    elif st[len(st)-7:]=="_LUAPTR":
        return st[:len(st)-7]+"*"
    elif st[len(st)-4:]=="_LUA":
        return st[:len(st)-4]
    else:
        return st

class ReplaceType:
    def __init__(self,oldName,oldExtra,oldArray,newName,newExtra,newArray):
        self.OldName=oldName
        self.OldExtra=oldExtra
        self.OldArray=oldArray
        self.NewName=newName
        self.NewExtra=newExtra
        self.NewArray=newArray
    def oldEquals(self,a):
        if a.OldName==self.OldName and a.OldExtra==self.OldExtra and a.OldArray==self.OldArray:
            return True
        return False
def getTableWithoutEqualSpecifier(f):
    ntbl=[]
    for x in f:
        if len(x)!=0:
            if x[0]!="=":
                ntbl.append(x)
    return ntbl
def tableHasEqualSpecifier(f):
    for x in f:
        if len(x)!=0:
            if x[0]=="=":
                return True
    return False

def tableEquals(ff,ss):
    f=getTableWithoutEqualSpecifier(ff)
    s=getTableWithoutEqualSpecifier(ss)
    if len(f)!=len(s):
        return False
    for x in range(0,len(f)):
        if f[x]!=s[x]:
            return False
    return True
    
def tableContains(f,r):
    for x in f:
        if tableEquals(x,r):
            return True
    return False
class ConvertObject:
    def __init__(self,nm,ptr,ref,nor,tmpl):
        self.pointer=ptr=="True"
        self.reference=ref=="True"
        self.parseTemplates(tmpl)
        self.name=nm
        self.normal=nor=="True"
    def merge(self,x):
        if self.name!=x.name:
            return False
        if self.pointer or x.pointer:
            self.pointer=True
        if self.reference or x.reference:
            self.reference=True
        if self.normal or x.normal:
            self.normal=True
        for xx in x.definedTemplates:
            if tableContains(self.definedTemplates,xx)==False:
                self.definedTemplates.append(xx)
    def removeEmptyTemplates(self):
        ntbl=[]
        for x in self.definedTemplates:
            if len(x)!=0:
                ntbl.append(x)
        self.definedTemplates=ntbl
    def parseTemplates(self,x):
        self.definedTemplates=[]
        defTable=x.split("|")
        for x in defTable:
            p=x.split(";")
            currTbl=[]
            for xx in p:
                currTbl.append(xx)
            self.definedTemplates.append(currTbl)
    def equals(self,a):
        if self.name==a.name:
            return True
        return False
def convertDefinedTemplates(x):
    for y in range(0,len(x.data)):
        for tt in x.data[y].definedTemplates:
            for t in tt:
                rt=t.replace(" *","")
                rt=rt.replace("*","")
                if x.getFromName(rt)!=None:
                    if t.count("*")>0:
                        t=rt+"_LUAPTR"
                    else:
                        t=rt="_LUA"
            
class ReplaceTypeArray:
    def __init__(self):
        self.data=[]
    def exist(self,x):
        for p in self.data:
            if p.oldEquals(x):
                return True
        return False
    def append(self,x):
        if self.exist(x)!=True:
            self.data.append(x)
            
class ConvertObjectArray:
    def __init__(self):
        self.data=[]
    def exist(self,x):
        for p in self.data:
            if p.equals(x):
                return True
        return False
    def getFromName(self,n):
        for p in self.data:
            if p.name==n:
                return p
        return None

    def append(self,x):
        if self.exist(x)==False:
            self.data.append(x)
        else:
            for p in self.data:
                if p.equals(x):
                    p.merge(x)

replaceTypes=ReplaceTypeArray()
convertObjects=ConvertObjectArray()
def replaceType(t):
    nt=CPPparse._Type()
    nt.data=t.data
    for r in replaceTypes.data:
        if t["name"]==r.OldName or r.OldName=="__ANY__":
            if t["extra"]==r.OldExtra or r.OldExtra=="__ANY__":
                if t["array"]==r.OldArray or r.OldArray=="__ANY__":
                    if r.NewName!="__SAME__":
                        nt.data["name"]=r.NewName
                    if r.NewExtra!="__SAME__":
                        nt.data["extra"]=r.NewExtra
                    if r.NewArray!="__SAME__":
                        nt.data["array"]=r.NewArray
    contbl=[]

    if nt.data.has_key("templatesConverted")!=True:
        for x in range(0,len(nt["templates"])):
            nt["templates"][x]=replaceType(nt["templates"][x])
            if nt["templates"][x]["isTemplate"]==True:
                if len(nt["templates"][x]["name"])<4 or nt["templates"][x]["name"][len(nt["templates"][x]["name"])-4:]!="_GET":
                    n=CPPparse._Type()
                    n.parseType(nt["templates"][x]["name"]+"_GET",0)
                    n.data["isTemplate"]=True
                    contbl.append(n)
            else:
                if checkLuaType(nt["templates"][x]["name"]):
                    n=CPPparse._Type()
                    n.parseType("darklua::TypeLuaConverter<"+nt["templates"][x]["fullname"]+","+getOldTypeFromLua(nt["templates"][x]["fullname"])+">",0)
                    contbl.append(n)
                else:
                    n=CPPparse._Type()
                    n.parseType("darklua::TypeNoneConverter<"+nt["templates"][x]["fullname"]+">",0)
                    contbl.append(n)
        nt.data["templatesConverted"]=True
    nt.data["templates"]=nt["templates"]+contbl
    nt.reloadFullname()
    nt.reloadTemplateName()
    return nt

def convertToReplace():
    for c in convertObjects.data:
        
        if c.pointer:
            x=ReplaceType(c.name,"*","__ANY__",c.name+"_LUAPTR","","__SAME__")
            replaceTypes.append(x)
        #if c.reference:
        #    x=ReplaceType(c.name,"&","__ANY__",c.name+"_LUAREF","","__SAME__")
       #     replaceTypes.append(x)
        if c.normal:
            x=ReplaceType(c.name,"&","__ANY__",c.name+"_LUA","","__SAME__")
            replaceTypes.append(x)
            x=ReplaceType(c.name,"","__ANY__",c.name+"_LUA","","__SAME__")
            replaceTypes.append(x)
def readConfig(fname):
    f=open(fname,"r")
    readConvertType=False
    readReplaceType=False
    data=[]
    ldata=0
    for x in f.readlines():
        x=x.replace("\n","")
        if readConvertType==False and readReplaceType==False:
            if x=="REPLACE_TYPE":
                readReplaceType=True
                ldata=0
                data=[]
            elif x=="CONVERT_OBJECT":
                readConvertType=True
                ldata=0
                data=[]
        elif readConvertType==True:
            if x=="__NONE__":
                x=""
            data.append(x)
            ldata=ldata+1
            if ldata>4:
                pp=ConvertObject(data[0],data[1],data[2],data[3],data[4])
                readConvertType=False
                convertObjects.append(pp)
        elif readReplaceType==True:
            if x=="__NONE__":
                x=""
            data.append(x)
            ldata=ldata+1
            if ldata>5:
                pp=ReplaceType(data[0],data[1],data[2],data[3],data[4],data[5])
                readReplaceType=False
                #replaceTypes.append(pp)
    f.close()
    


def readParsingFile(fname):
    ns=[]
    f=open(fname,"r")
    for x in f.readlines():
        rstr=x
        rstr=rstr.replace("\n","")
        nss=CPPparse.parse(rstr,-1,True)
        ns.append(nss)
    f.close()
    retNs=ns[0]
    
    for x in ns:
        retNs.merge(x,False)
    return retNs
    
    
    
configFile="config.txt"
readConfig("scan.txt")
globalNamespace=readParsingFile(configFile)
for x in globalNamespace.getObjects("Type"):
    x=replaceType(x)
convertToReplace()

for x in globalNamespace.getObjects("Type"):
    x=replaceType(x)


class BindFuncTbl:
    def __init__(self):
        self.data=[]
    def exist(self,s):
        for x in self.data:
            if x==s:
                return True
        return False
    def append(self,s):
        if self.exist(s)==False:
            self.data.append(s)


def printNamespace(ns,asOpen):
    for n in ns:
        if n!="":
            if asOpen:
                PrintClass.prt("namespace "+n)
                PrintClass.prt("{")
                PrintClass.dt()
            else:
                PrintClass.it()
                PrintClass.prt("}")

def printClassAll(c,typ,ctype,bindStr):
    
    namespaces=c["namespace"].split("::")    
    preprocessor="_"+str(c["name"]+typ+"_H_").upper()+"_INCLUDED_"
    
    #---------------
    #H FILE
    
    print "FILEH"
    
    print c["name"]+typ+".h"
    
    print "#ifndef "+preprocessor
    print "#define "+preprocessor
    
    nameWithTemplate=""
    nameWithTemplateNew=""
    nameWithTemplateNewGet=""
    fullTemplate=""
    fullTemplateGet=""
    first=True
    for x in c["templates"]:
        if first:
            nameWithTemplate=nameWithTemplate+"<"
            fullTemplate=fullTemplate+"template<"
            nameWithTemplateNew=nameWithTemplateNew+"<"
            first=False
        else:
            nameWithTemplate=nameWithTemplate+","
            fullTemplate=fullTemplate+","
            nameWithTemplateNewGet=nameWithTemplateNewGet+","
            fullTemplateGet=fullTemplateGet+","
        fullTemplate=fullTemplate+"typename "+x
        
        fullTemplateGet=fullTemplateGet+"typename "+x+"_GET"
        nameWithTemplate=nameWithTemplate+x
        nameWithTemplateNew=nameWithTemplateNew+x
        
        nameWithTemplateNewGet=nameWithTemplateNewGet+x+"_GET"
    if first==False:
        fullTemplate=fullTemplate+","+fullTemplateGet+">"
        nameWithTemplateNew=nameWithTemplateNew+nameWithTemplateNewGet+">"
        nameWithTemplate=nameWithTemplate+">"
        
    for x in c.getObjects("Type"):
        if x["name"]+nameWithTemplate==x["templatename"]:
            x.parseType(x["name"]+nameWithTemplateNew+x["extra"],0)
    
    printNamespace(namespaces,True)
    
    if ctype.normal:
        PrintClass.prt(fullTemplate)
        PrintClass.prt("class "+c["name"]+"_LUA;")
    if ctype.reference:
        PrintClass.prt(fullTemplate)
        PrintClass.prt("class "+c["name"]+"_LUAREF;")
    if ctype.pointer:
        PrintClass.prt(fullTemplate)
        PrintClass.prt("class "+c["name"]+"_LUAPTR;")
        
    
    PrintClass.writeClassH(c,typ)
    
    
    printNamespace(namespaces,False)
    
    
    print "#endif"
    
    
    #END H FILE
    #----------------
    
    
    #----------------
    #CPP FILE
    
    print "FILECPP"
    print c["name"]+typ+"cpp.h"
    print "extern \"C\" {"
    print "#include \"lua.h\""
    print "#include \"lualib.h\""
    print "#include \"lauxlib.h\""
    print "#include \"luabind/luabind.hpp\""
    print "}"
    
    
    print "#include \""+c["name"]+typ+".h\""
        
        
    printNamespace(namespaces,True)
    
    acType="."
    if typ=="_LUAPTR":
        acType="->"
    
    PrintClass.writeClassDataCPP(c["public"],acType,c["name"]+typ,c["name"],c)
    
    
    printNamespace(namespaces,False)
    
    
    if len(ctype.definedTemplates)==0:
        bindStr=bindStr+c["namespace"]+"::"+c["name"]+typ+"::_LUAbindClass(state,\""+c["name"]+"\");"
    for t in ctype.definedTemplates:
        if len(getTableWithoutEqualSpecifier(t))!=len(c["templates"]):
            continue
        tst=""
        nameWithTemplate=c["name"]
        
        for i in t:

            
            if len(i)>0:
                if i[0]=="=":
                    nameWithTemplate=i[1:]
                else:
                    if tst!="":
                        tst=tst+","
                    nameWithTemplate=nameWithTemplate+i
                    tst=tst+i
                    tst=tst+","
                    if checkLuaType(i):
                        tst=tst+"darklua::TypeLuaConverter<"+getOldTypeFromLua(i)+","+i+">"
                    else:
                        tst=tst+"darklua::TypeNoneConverter<"+i+">"
        if tst=="":
            bindStr.append(c["namespace"]+"::"+c["name"]+typ+"::_LUAbindClass(state,\""+nameWithTemplate+"\");")
        else:
            bindStr.append(c["namespace"]+"::"+c["name"]+typ+"<"+tst+">::_LUAbindClass(state,\""+nameWithTemplate+"\");")
def exGetClassData(nam):
    return convertObjects.getFromName(nam)
    
PrintClass.getClassData=exGetClassData
def finalPrintClass(c):
    if c["public"].isDataEmpty()==False or c["protected"].isDataEmpty()==False or c["private"].isDataEmpty()==False and c["inner"]==False:
        bindStr=BindFuncTbl()
        ctype=convertObjects.getFromName(c["name"])
        if ctype!=None:
            if ctype.normal:
                printClassAll(c,"_LUA",ctype,bindStr)
            if ctype.reference:
                printClassAll(c,"_LUAREF",ctype,bindStr)
            if ctype.pointer:
                printClassAll(c,"_LUAPTR",ctype,bindStr)
            print "FILEH"
            print c["name"]+"_BIND.h"
            print "void bindAllLUA"+c["name"]+"(lua_State *state)"
            print "{"
            for x in bindStr.data:
                print "\t"+x
            print "}"
convertDefinedTemplates(convertObjects)
for c in globalNamespace.getObjects("Class"):
    finalPrintClass(c)
for c in globalNamespace.getObjects("Enum"):
    ctype=convertObjects.getFromName(c["name"])
    if ctype!=None and c["inner"]==False:
        print "FILEH"
        print c["name"]+"_BIND.h"
        print "void bindAllLUA"+c["name"]+"(lua_State *state)"
        print "{"
        PrintClass.dt()
        PrintClass.prt("luabind::module(state)")
        globalStr="luabind::globals(state)"
        namespaces=c["namespace"].split("::")
        for x in namespaces:
            if x!="":
                PrintClass.prt("[")
                PrintClass.dt()
                PrintClass.prt("luabind::namespace_(\""+x+"\")")
                globalStr=globalStr+"[\""+x+"\"]"
        
        
        for x in namespaces:
            if x!="":
                PrintClass.it()
                PrintClass.prt("]")
        for v in c["rows"]:
            PrintClass.prt(globalStr+"[\""+v["name"]+"\"]="+str(v["value"]))
        PrintClass.it()
        PrintClass.prt("}")
for c in globalNamespace.getObjects("Function"):
    ctype=convertObjects.getFromName(c["name"])
    if ctype!=None:
        print "FILEH"
        print c["name"]+"_BIND.h"
        print "void bindAllLUA"+c["name"]+"(lua_State *state)"
        print "{"
        PrintClass.dt()
        PrintClass.prt("luabind::module(state)")
        namespaces=c["namespace"].split("::")
        for x in namespaces:
            if x!="":
                
                PrintClass.prt("[")
                PrintClass.dt()
                PrintClass.prt("luabind::namespace_(\""+x+"\")")
                
        params=""
        for p in c["parameters"]:
            if params!="":
                params=params+","
            params=params+p["type"]["fullname"]

        PrintClass.prt("luabind::def(\""+x["name"]+"\",("+x["returnType"]["fullname"]+"(*)("+params+"))&"+x["namespace"]+"::"+x["name"]+")")

        PrintClass.it()
        for x in namespaces:
            if x!="":
                PrintClass.it()
                PrintClass.prt("]")
        PrintClass.it()
        PrintClass.prt("}")
print "ENDCONVERT.PY_STOP_STD_OUT"

